import 'dart:convert';

import 'package:example/page/playground_page.dart';
import 'package:example/page/websocket_extension.dart';
import 'package:flujs/extension/console.dart';
import 'package:flujs_jsc/JSFValueJSCImpl.dart';
import 'package:flutter/material.dart';

final wsCode = '''
const ws = new WebSocket('wss://echo.websocket.org/');
console.log("[ws] create websocket");
ws.addEventListener('open', function (e) {
  console.log('[js] client: opened!');
  ws.send("hello, flujs!");
});
ws.addEventListener('message', function (e) {
  console.log('[js] client: received: e.data');
});
ws.addEventListener('error', function(e) {
  console.error('[js] client: error', e);
})
ws.addEventListener('close', function(e) {
  console.error('[js] client: close', e);
})
''';

class WebSocketPage extends StatefulWidget {
  const WebSocketPage({super.key});

  @override
  State<WebSocketPage> createState() => _WebSocketPageState();
}

class _WebSocketPageState extends State<WebSocketPage> {
  late var controller = PlaygroundController();
  @override
  void initState() {
    controller.qjsGctx.extension
        ?.chain(WebsocketExtension(controller.qjsGctx))
        .load();
    controller.jscGctx.extension
        ?.chain(WebsocketExtension(controller.jscGctx))
        .load();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return PlaygroundPage(
      code: wsCode,
      title: 'WebSocket',
      controller: controller,
      customOpts: [
        ElevatedButton(
          onPressed: () {
            controller.qjsGctx.eval('ws.send("hhhh")');
          },
          child: Text('qjs: send msg'),
        ),
        ElevatedButton(
          onPressed: () {
            controller.jscGctx.eval('ws.send("hhhh")');
          },
          child: Text('jsc: send msg'),
        ),
      ],
    );
  }
}

final ajvPreCode = '''
window = globalThis;
let ajv = new Ajv();
let schema = {
  type: 'Object',
  properties: {
    foo: { type: 'integer' },
    bar: { type: 'string' }
  },
  required: [ 'foo' ],
  additionalProperties: false
}
let validate = ajv.compile(schema)
''';

class AjvPage extends StatefulWidget {
  const AjvPage({super.key});

  @override
  State<AjvPage> createState() => _AjvPageState();
}

class _AjvPageState extends State<AjvPage> {
  final PlaygroundController controller = PlaygroundController();
  @override
  void initState() {
    super.initState();
    DefaultAssetBundle.of(context)
        .loadString('assets/ajv7.bundle.js')
        .then((v) {
      controller
        ..jscGctx.eval(v, sourceURL: 'assets/ajv7.bundle.js')
        ..jscGctx.eval(ajvPreCode, sourceURL: 'ajv.code')
        ..qjsGctx.eval(v, sourceURL: 'assets/ajv7.bundle.js')
        ..qjsGctx.eval(ajvPreCode, sourceURL: 'ajv.code');
    });
  }

  @override
  Widget build(BuildContext context) {
    return PlaygroundPage(
      code: ajvPreCode,
      title: 'AJV',
      controller: PlaygroundController(),
      replaceDefaultButton: true,
      customOpts: [
        ElevatedButton(
            onPressed: () {
              var keys =
                  controller.qjsGctx.globalObject.keys(controller.qjsGctx);
              Console.info('[keys] ${keys.toArray()}');
              final validateFn =
                  controller.qjsGctx.globalObject.getProperty('validate');
              if (!validateFn.isFunction()) {
                Console.error(
                    'validate is not a function. ${validateFn.toString()}');
                return;
              }
              final ret = validateFn.callAsFunction(arguments: [
                JSFValueJSCImpl.makeFromJSONString(
                    controller.qjsGctx, jsonEncode({'foo': 1, 'bar': 'abc'}))
              ]);
              if (ret.isBoolean()) {
                if (ret.toBoolean() == false) {
                  Console.info(
                      '[ajv] invalid json object ${ret.getProperty('errors').toString()}');
                } else {
                  Console.info('[ajv] ok: ${ret.toString()}');
                }
              } else {
                Console.info('[ajv] result = ${ret.toString()}');
              }
            },
            child: Text('qjs check')),
        ElevatedButton(
            onPressed: () {
              var keys =
                  controller.jscGctx.globalObject.keys(controller.jscGctx);
              Console.info('[keys] ${keys.toArray()}');
              final validateFn =
                  controller.jscGctx.globalObject.getProperty('validate');
              if (!validateFn.isFunction()) {
                Console.error('validate is not a function');
                return;
              }
              final ret = validateFn.callAsFunction(arguments: [
                JSFValueJSCImpl.makeFromJSONString(
                    controller.jscGctx, jsonEncode({'foo': 1, 'bar': 'abc'}))
              ]);
              if (ret.isBoolean()) {
                if (ret.toBoolean() == false) {
                  Console.info(
                      '[ajv] invalid json object ${ret.getProperty('errors').toString()}');
                } else {
                  Console.info('[ajv] ok: ${ret.toString()}');
                }
              } else {
                Console.info('[ajv] result = ${ret.toString()}');
              }
            },
            child: Text('jsc check'))
      ],
    );
  }
}
